const _ = require("lodash");
const { readAllValues } = require("../awakened-potential/helpers/readAllValues.js");

/**
 * 热号 + 冷号预测
 */
function predictNextNumber(history, options = {}) {
  const hotCount = options.hotCount || 12;
  const coldCount = options.coldCount || 12;

  const countMap = Array(50).fill(0);

  for (const item of history) {
    const number = Number(item.number);
    if (number >= 1 && number <= 49) {
      countMap[number]++;
    }
  }

  const result = countMap.map((count, number) => ({ number, count })).slice(1);

  const hotNumbers = _.orderBy(result, ["count", "number"], ["desc", "asc"])
    .slice(0, hotCount)
    .map(item => item.number);

  const coldNumbers = _.orderBy(result, ["count", "number"], ["asc", "asc"])
    .slice(0, coldCount)
    .map(item => item.number);

  const recommend = _.uniq([...hotNumbers, ...coldNumbers]);

  return {
    hot: hotNumbers,
    cold: coldNumbers,
    recommend: recommend.sort((a, b) => a - b),
  };
}

/**
 * 一阶马尔科夫
 */
function buildMarkovMatrix(history) {
  const matrix = Array.from({ length: 50 }, () => Array(50).fill(0));

  for (let i = 1; i < history.length; i++) {
    const prev = Number(history[i - 1].number);
    const curr = Number(history[i].number);
    if (prev >= 1 && curr >= 1 && prev <= 49 && curr <= 49) {
      matrix[prev][curr]++;
    }
  }

  for (let i = 1; i <= 49; i++) {
    const row = matrix[i];
    const sum = row.reduce((a, b) => a + b, 0);
    if (sum > 0) {
      for (let j = 1; j <= 49; j++) {
        row[j] = row[j] / sum;
      }
    }
  }

  return matrix;
}

function getMarkovPrediction(prev, matrix, topN = 5) {
  const row = matrix[prev];
  if (!row) return [];

  return row
    .map((prob, number) => ({ number, prob }))
    .slice(1)
    .filter(item => item.prob > 0)
    .sort((a, b) => b.prob - a.prob)
    .slice(0, topN)
    .map(item => item.number);
}

/**
 * 二阶马尔科夫
 */
function buildSecondOrderMarkovMatrix(history) {
  const matrix = Array.from({ length: 50 }, () =>
    Array.from({ length: 50 }, () => Array(50).fill(0))
  );

  for (let i = 2; i < history.length; i++) {
    const p1 = Number(history[i - 2].number);
    const p2 = Number(history[i - 1].number);
    const curr = Number(history[i].number);

    if (p1 >= 1 && p2 >= 1 && curr >= 1 && p1 <= 49 && p2 <= 49 && curr <= 49) {
      matrix[p1][p2][curr]++;
    }
  }

  for (let i = 1; i <= 49; i++) {
    for (let j = 1; j <= 49; j++) {
      const row = matrix[i][j];
      const sum = row.reduce((a, b) => a + b, 0);
      if (sum > 0) {
        for (let k = 1; k <= 49; k++) {
          row[k] = row[k] / sum;
        }
      }
    }
  }

  return matrix;
}

function getSecondOrderMarkovPrediction(p1, p2, matrix, topN = 5) {
  const row = matrix[p1]?.[p2];
  if (!row) return [];

  return row
    .map((prob, number) => ({ number, prob }))
    .slice(1)
    .filter(item => item.prob > 0)
    .sort((a, b) => b.prob - a.prob)
    .slice(0, topN)
    .map(item => item.number);
}

/**
 * 三阶马尔科夫
 */
function buildThirdOrderMarkovMatrix(history) {
  const matrix = Array.from({ length: 50 }, () =>
    Array.from({ length: 50 }, () =>
      Array.from({ length: 50 }, () => Array(50).fill(0))
    )
  );

  for (let i = 3; i < history.length; i++) {
    const p1 = Number(history[i - 3].number);
    const p2 = Number(history[i - 2].number);
    const p3 = Number(history[i - 1].number);
    const curr = Number(history[i].number);

    if ([p1, p2, p3, curr].every(n => n >= 1 && n <= 49)) {
      matrix[p1][p2][p3][curr]++;
    }
  }

  for (let i = 1; i <= 49; i++) {
    for (let j = 1; j <= 49; j++) {
      for (let k = 1; k <= 49; k++) {
        const row = matrix[i][j][k];
        const sum = row.reduce((a, b) => a + b, 0);
        if (sum > 0) {
          for (let t = 1; t <= 49; t++) {
            row[t] = row[t] / sum;
          }
        }
      }
    }
  }

  return matrix;
}

function getThirdOrderMarkovPrediction(p1, p2, p3, matrix, topN = 5) {
  const row = matrix[p1]?.[p2]?.[p3];
  if (!row) return [];

  return row
    .map((prob, number) => ({ number, prob }))
    .slice(1)
    .filter(item => item.prob > 0)
    .sort((a, b) => b.prob - a.prob)
    .slice(0, topN)
    .map(item => item.number);
}

/**
 * 连续段落分析
 */
function analyzeStreaks(arr) {
  let streaks1 = [];
  let streaks0 = [];

  let current = arr[0];
  let count = 1;

  for (let i = 1; i < arr.length; i++) {
    if (arr[i] === current) {
      count++;
    } else {
      if (current === 1) streaks1.push(count);
      else streaks0.push(count);
      current = arr[i];
      count = 1;
    }
  }

  if (current === 1) streaks1.push(count);
  else streaks0.push(count);

  const maxStreak1 = Math.max(...streaks1, 0);
  const maxStreak0 = Math.max(...streaks0, 0);

  const avgStreak1 =
    streaks1.length > 0
      ? (streaks1.reduce((a, b) => a + b, 0) / streaks1.length).toFixed(2)
      : "0.00";
  const avgStreak0 =
    streaks0.length > 0
      ? (streaks0.reduce((a, b) => a + b, 0) / streaks0.length).toFixed(2)
      : "0.00";

  return {
    maxStreak1,
    maxStreak0,
    avgStreak1,
    avgStreak0,
    streaks1,
    streaks0,
  };
}

// ========== ✅ 主逻辑 ==========

const historyDataRaw = readAllValues("m");
const historyData = historyDataRaw.map(item => ({
  time: item.time,
  number: Number(item.number),
}));

const windowSize = 100;        // 滑动窗口大小，用于历史数据分析
const hotCount = 21;           // 热号数量，选择出现频率最高的前21个号码
const coldCount = 11;          // 冷号数量，选择出现频率最低的前11个号码
const markovTopN = 5;          // 一阶马尔科夫链预测的推荐号码数量
const markov2TopN = 5;         // 二阶马尔科夫链预测的推荐号码数量
const markov3TopN = 5;         // 三阶马尔科夫链预测的推荐号码数量

let correct = 0;               // 预测正确的次数统计
let wrong = 0;                 // 预测错误的次数统计
let hitArray = [];             // 存储每次预测的命中情况（1表示命中，0表示未命中）

console.log(`\n🧠 开始滑动预测，共 ${historyData.length - windowSize} 次预测：\n`);

let maxFinalRecommendLen = 32

for (let i = windowSize; i < historyData.length; i++) {
  const windowData = historyData.slice(i - windowSize, i);
  const actual = historyData[i];

  const p1 = historyData[i - 3]?.number || 0;
  const p2 = historyData[i - 2]?.number || 0;
  const p3 = historyData[i - 1]?.number || 0;

  const prediction = predictNextNumber(windowData, { hotCount, coldCount });

  const markovMatrix = buildMarkovMatrix(historyData.slice(0, i));
  const markov2Matrix = buildSecondOrderMarkovMatrix(historyData.slice(0, i));
  const markov3Matrix = buildThirdOrderMarkovMatrix(historyData.slice(0, i));

  const m1 = getMarkovPrediction(p3, markovMatrix, markovTopN);
  const m2 = getSecondOrderMarkovPrediction(p2, p3, markov2Matrix, markov2TopN);
  const m3 = getThirdOrderMarkovPrediction(p1, p2, p3, markov3Matrix, markov3TopN);

  const finalRecommend = _.uniq([
    ...prediction.recommend,
    ...m1,
    ...m2,
    ...m3,
  ]).sort((a, b) => a - b);

  const hit = finalRecommend.includes(actual.number);
  hitArray.push(hit ? 1 : 0);
  if (hit) correct++;
  else wrong++;
  if(finalRecommend.length !== 32) {
    //   console.log(`📅 第${i + 1}期（${actual.time}）`);
    //   console.log(`🔥 热号(${prediction.hot.length}):`, prediction.hot.join(", "));
    //   console.log(`❄️ 冷号(${prediction.cold.length}):`, prediction.cold.join(", "));
    //   console.log(`🧠 一阶马尔科夫(${m1.length}):`, m1.join(", "));
    //   console.log(`🧠 二阶马尔科夫(${m2.length}):`, m2.join(", "));
    //   console.log(`🧠 三阶马尔科夫(${m3.length}):`, m3.join(", "));
    //   console.log(`🎯 推荐(${finalRecommend.length}):`, finalRecommend.join(", "));
    //   console.log(`✅ 实际号码: ${actual.number} → 是否命中: ${hit ? "✅ 是" : "❌ 否"}`);
    //   console.log("---------------------------------------------------\n");
    if(finalRecommend.length > maxFinalRecommendLen) {
      maxFinalRecommendLen = finalRecommend.length
      console.log(maxFinalRecommendLen)
    }
  }

}

// ✅ 总结
const total = correct + wrong;
const accuracy = total > 0 ? ((correct / total) * 100).toFixed(2) : "0.00";
const { maxStreak1, maxStreak0, avgStreak1, avgStreak0, streaks1, streaks0 } = analyzeStreaks(hitArray);

console.log("\n🎯 预测结果统计");
console.log(`总预测期数: ${total}`);
console.log(`✅ 命中期数: ${correct}`);
console.log(`❌ 错误期数: ${wrong}`);
console.log(`📊 命中率: ${accuracy}%`);

console.log("\n📈 连续预测表现分析：");
console.log(`✅ 最大连续命中次数: ${maxStreak1} 次`);
console.log(`❌ 最大连续失败次数: ${maxStreak0} 次`);
console.log(`✅ 成功段落数量: ${streaks1.length}`);
console.log(`❌ 错误段落数量: ${streaks0.length}`);
console.log(`✅ 成功段落平均长度: ${avgStreak1} 次`);
console.log(`❌ 错误段落平均长度: ${avgStreak0} 次`);


/*
🎯 预测结果统计
总预测期数: 1145
✅ 命中期数: 776
❌ 错误期数: 369
📊 命中率: 67.77%

📈 连续预测表现分析：
✅ 最大连续命中次数: 14 次
❌ 最大连续失败次数: 5 次
✅ 成功段落数量: 244
❌ 错误段落数量: 243
✅ 成功段落平均长度: 3.18 次
❌ 错误段落平均长度: 1.52 次
//*/